package com.zhida.chatservice.service.impl;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.zhida.chatservice.mapper.WsGroupMapper;
import com.zhida.chatservice.service.WebSocket;
import com.zhida.chatservice.utils.MsgUtil;
import com.zhida.common.entity.AllMessage;
import com.zhida.common.entity.WsGroup;
import com.zhida.common.utils.ObjectUtil;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.socket.BinaryMessage;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;

import java.io.IOException;
import java.util.*;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.atomic.AtomicInteger;

import static com.zhida.common.utils.StaticKeyUtil.*;

@Service
@Slf4j
public class WebSocketImpl implements WebSocket {
    /**
     * 在线连接数（线程安全）
     */
    private final AtomicInteger connectionCount = new AtomicInteger(0);

    /**
     * 线程安全的无序集合（存储会话）
     */
    private final CopyOnWriteArraySet<WebSocketSession> sessions = new CopyOnWriteArraySet<>();

    /**
     * 群聊列表 (存储会话)
     */
    private final ArrayList<Map<String,ArrayList<String>>> groupList = new ArrayList<>();

    @Resource
    RedisTemplate<String,String> redisTemplate;
    @Resource
    WsGroupMapper wsGroupMapper;

    @Override
    public void handleOpen(WebSocketSession session) {
//        模拟将用户session存入缓存 redis(sessions)
//        System.err.println(session);
//        截取 第一个 = 后面内容为sessionID
        String id = session.toString().substring(session.toString().indexOf("=") + 1,session.toString().indexOf(","));
//        永久存到redis
        try {
            String jsonUser = new ObjectMapper().writeValueAsString(Map.of("sessionId",id,"username",session.getAttributes().get("username")));
            redisTemplate.opsForValue().set(WS_USER_KEY + session.getAttributes().get("username"),jsonUser);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
//          将用户信息存入变量
        saveInGroupSessions(session);

        sessions.add(session);
        int count = connectionCount.incrementAndGet();
        log.info("当前在线用户：{}", count);
    }

    private void saveInGroupSessions(WebSocketSession session) {
//        取用户名
        String username = session.getAttributes().get("username").toString();
        List<String> groups = getUserGroup(username);
        for (String group : groups) {
//            判断groupList中是否存在group
            if (!groupList.stream().anyMatch(map -> map.containsKey(group))) {
                log.info("创建群聊大厅：{}，用户：{}加入群聊大厅",group,username);
                groupList.add(Map.of(group, new ArrayList<>(List.of(username))));
            } else {

                groupList.stream().filter(map -> map.containsKey(group)).forEach(map -> map.get(group).add(username));
                log.info("用户：{}加入群聊大厅：{}",username,group);
            }
        }
    }

    @Override
    public void handleClose(WebSocketSession session) {
        String username = session.getAttributes().get("username").toString();
        sessions.remove(session);
//        从groupList中移除username
        for (Map<String, ArrayList<String>> stringArrayListMap : groupList) {
            stringArrayListMap.forEach( (k,v) -> v.remove(username));
        }
        int count = connectionCount.decrementAndGet();
//        从redis中移除
        redisTemplate.delete(WS_USER_KEY + username);
        log.info("当前在线用户：{}", count);
    }

    @Override
    public void handleMessage(WebSocketSession session, String message) {
//        从message中解析到目标用户user_id
        try {
            JsonNode jsonMsg = ObjectUtil.JsonStr2Object(message);
//            尝试从reids中获取目标用户
//            从sessions中取出对应的session
            String from = session.getAttributes().get("username").toString();
            message = message.replace("}",",\"from\":\"" + from + "\"}");
            sendMessage(session, message);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
//        客户端得到信息之后，将信息转发给用户

    }

    @Override
    public void handleMessage(WebSocketSession session, BinaryMessage message){
        System.out.println(message);
    }

    @Override
    public void sendMessage(WebSocketSession session, String message) throws IOException {
        JsonNode jsonMsg = ObjectUtil.JsonStr2Object(message);
//        用户是否在线
        if (jsonMsg.get("group") != null){
            WsGroup wsGroup = wsGroupMapper.selectById(jsonMsg.get("group").asText());
            //  群聊是否全员禁言
            if (wsGroup.getIsMute() == 1){
                return;
            } else {
                //  用户是否被禁言
                String s = redisTemplate.opsForValue().get(MUTE_KEY + jsonMsg.get("group").asText() + ":" + session.getAttributes().get("username"));
                if (StringUtils.isNotBlank(s)){
                    sendGroupMessage(session,message);
                }
            }
            return;
        }
        String to = redisTemplate.opsForValue().get(WS_USER_KEY + jsonMsg.get("to").asText());
        if (to != null){
            System.out.println(jsonMsg);
            System.out.println(to);
            JsonNode jsonTo = ObjectUtil.JsonStr2Object(to);
//            判断用户是否在线
            if (jsonTo != null) {
                this.sendMessage(jsonTo.get("username").asText(), message);
            } else{
                System.err.println("故意的");
                throw new NullPointerException("跳转catch捕获临时消息");
            }
        } else {
            System.out.println("对方不在线");
            MsgUtil.cachingOfflineMsg(redisTemplate,message);
        }
        MsgUtil.cachingAllMsg(redisTemplate,message);
    }

    private void sendGroupMessage(WebSocketSession session, String message) throws IOException {
//        向所有group中的成员发送信息
        JsonNode jsonMsg = ObjectUtil.JsonStr2Object(message);
        String group = jsonMsg.get("group").asText();
        String username = jsonMsg.get("from").asText();
//        遍历groupList,找到和group相同的key
        for (Map<String, ArrayList<String>> stringArrayListMap : groupList) {
            if (stringArrayListMap.get(group)!=null){
                for (String to : stringArrayListMap.get(group)) {
                    if (!session.getAttributes().get("username").equals(to)) {
                        sendMessage(to,message);
                    }
                }
            }
        }
        String time = String.valueOf(System.currentTimeMillis());
//        将消息存入redis
        if (redisTemplate.opsForValue().get(WS_GROUP_MSG_KEY + group) == null){
            ArrayList<AllMessage> group_msg = new ArrayList<>();
//            取当前时间戳
            group_msg.add(new AllMessage(username,time,ObjectUtil.JsonStr2Object(message).get("msg").asText()));
            redisTemplate.opsForValue().set(WS_GROUP_MSG_KEY + group, ObjectUtil.Object2JsonStr(group_msg));
        } else {
            ObjectMapper mapper = new ObjectMapper();
            ArrayList<AllMessage> group_msg = mapper.readValue(redisTemplate.opsForValue().get(WS_GROUP_MSG_KEY + group),ArrayList.class);
            group_msg.add(new AllMessage(username,time,ObjectUtil.JsonStr2Object(message).get("msg").asText()));
            redisTemplate.opsForValue().set(WS_GROUP_MSG_KEY + group, ObjectUtil.Object2JsonStr(group_msg));
        }

    }

    @Override
    public void sendMessage(String toUsername, TextMessage message) throws IOException {
        Optional<WebSocketSession> userSession = sessions.stream().filter(session -> {
            if (!session.isOpen()) {
                return false;
            }
            Map<String, Object> attributes = session.getAttributes();
            if (!attributes.containsKey("username")){
                return false;
            }
            String username = (String) attributes.get("username");
            return username.equals(toUsername);
        }).findFirst();
        if (userSession.isPresent()) {
            userSession.get().sendMessage(message);
        }
    }

    @Override
    public void sendMessage(String userId, String message) throws IOException {
        this.sendMessage(userId, new TextMessage(message));
    }

    @Override
    public void sendMessage(WebSocketSession session, TextMessage message) throws IOException {
        session.sendMessage(message);
    }

    @Override
    public void broadCast(String message) throws IOException {
        for (WebSocketSession session : sessions) {
            if (!session.isOpen()) {
                continue;
            }
            this.sendMessage(session, message);
        }
    }

    @Override
    public void broadCast(TextMessage message) throws IOException {
        for (WebSocketSession session : sessions) {
            if (!session.isOpen()) {
                continue;
            }
            session.sendMessage(message);
        }
    }

    @Override
    public void handleError(WebSocketSession session, Throwable error) {
        log.error("websocket error：{}，session id：{}", error.getMessage(), session.getId());
        log.error("", error);
    }

    @Override
    public Set<WebSocketSession> getSessions() {
        return sessions;
    }

    @Override
    public int getConnectionCount() {
        return connectionCount.get();
    }

    public List<String> getUserGroup(String username){
//        从数据库获取用户所加入的群聊
        return wsGroupMapper.getGroups("%#" + username + ",%");
    }
}
